﻿using Abp.Application.Services.Dto;
using Abp.AutoMapper;
using Abp.Linq.Extensions;
using Hicap.QRCodeWarehouse.Application.Dto;
using Hicap.QRCodeWarehouse.Application.Dto.Common;
using Hicap.QRCodeWarehouse.Core.Managers;
using Hicap.QRCodeWarehouse.Core.Models.DbSet;
using Hicap.QRCodeWarehouse.Core.Models.Transfer;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading.Tasks;
using JsonConvert = Newtonsoft.Json.JsonConvert;

namespace Hicap.QRCodeWarehouse.Application.App

{
    /// <summary>
    /// File repository service
    /// </summary>
    public class FileRepositoryAppService : QrCodeWarehouseApplicationBase<FileRepository, FileRepositoryListDto, FileRepositoryEditDto>
    {
        private readonly IFileRepositoryManager _manager;

        public FileRepositoryAppService(IFileRepositoryManager manager) : base(manager)
        {
            _manager = manager;
        }

        ///<inheritdoc cref="Upsert" />
        /// <remarks>Hidden</remarks>
        [NonAction]
        public override Task<int> Upsert(CreateOrUpdateInput<FileRepositoryEditDto> input)
        {
            return base.Upsert(input);
        }

        ///<inheritdoc cref="BatchUpsert" />
        /// <remarks>Hidden</remarks>
        [NonAction]
        public override Task<int> BatchUpsert(List<CreateOrUpdateInput<FileRepositoryEditDto>> inputs)
        {
            return base.BatchUpsert(inputs);
        }

        /// <summary>
        /// Upload data zip file to ftpserver
        /// </summary>
        /// <param name="file">IFormFile</param>
        /// <param name="inputJson">string</param>
        /// <returns></returns>
        public async Task Upload(IFormFile file, string inputJson)
        {
            //Deserialize to FileRepositoryEditDto
            FileRepositoryEditDto input = JsonConvert.DeserializeObject<FileRepositoryEditDto>(inputJson);

            //upload file
            FileRepository entity = input.MapTo<FileRepository>();
            using (Stream stream = await Task.Run(() => file?.OpenReadStream()))
            {
                await _manager.Upload(entity, stream);
            }
        }

        /// <summary>
        /// Download data zip file
        /// </summary>
        /// <param name="input">FileRepositoryEditDto</param>
        /// <returns>FileResult</returns>
        public async Task<FileResult> Download(FileRepositoryEditDto input)
        {
            using (MemoryStream stream = new MemoryStream())
            {
                //download by file id,return stream
                await _manager.Download(input.Id.Value, stream);

                return new FileContentResult(stream.ToArray(), "application/zip");
            }
        }

        /// <summary>
        /// Restore from recycle bin
        /// </summary>
        /// <param name="input">int</param>
        /// <returns></returns>
        public async Task RestoreWithRecycleBin([FromBody]int input)
        {
            await _manager.RestoreWithRecycleBin(input);
        }

        /// <summary>
        /// Batch restore from recycle bin
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task BatchRestoreWithRecycleBin(List<int> input)
        {
            await _manager.BatchRestoreWithRecycleBin(input);
        }

        /// <summary>
        /// Delete from recycle bin
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task DeleteWithRecycleBin(int input)
        {
            await _manager.DeleteWithRecycleBin(input);
        }

        /// <summary>
        /// Batch delete from recycle bin
        /// </summary>
        /// <param name="input">List&lt;int&gt;</param>
        /// <returns></returns>
        public async Task BatchDeleteWithRecycleBin(List<int> input)
        {
            await _manager.BatchDeleteWithRecycleBin(input);
        }

        /// <summary>
        /// Query paged data from recycle bin
        /// </summary>
        /// <param name="queryInput"></param>
        /// <returns></returns>
        public async Task<PagedResultDto<FileRepositoryListDto>> PagedDatasWithRecycleBin(QueryInput queryInput)
        {
            IQueryable<FileRepository> query = GetQuery(_manager.GetQueryWithRecycleBin(null), queryInput);

            int count = query.Count();

            List<FileRepository> result = await query
                .OrderBy(queryInput.Sorting)
                .PageBy(queryInput)
                .ToListAsync();

            List<FileRepositoryListDto> resultListDto = result.MapTo<List<FileRepositoryListDto>>();

            return new PagedResultDto<FileRepositoryListDto>(
                count,
                resultListDto
            );
        }

        /// <summary>
        /// Import datas from file repository by command
        /// </summary>
        /// <param name="cmd">ImportFileCommandDto</param>
        /// <returns></returns>
        public async Task ImportDataFile(ImportFileCommandDto cmd)
        {
            await _manager.ImportDataFile(cmd);
        }

        /// <summary>
        /// Make data zip file
        /// </summary>
        /// <param name="cmd">TakeFileCommandDto</param>
        /// <returns></returns>
        public async Task MakeDataFile(TakeFileCommandDto cmd)
        {
            await _manager.MakeDataFile(cmd);
        }
    }
}